UPS was written by Mark Russell <mtr.ukc.ac.uk>.

Six months ago I ported the UPS debugger to Linux.  Since then I
have found a few bugs in the port and I added support for more UPS
features.  More importantly, GCC seems to have changed the debugging
information it generates in such a way that the old UPS will hardly
run at all.  So I have patched things up as best as I can and created
a second revision of the diffs.

The file is currently available at:

  sunsite.unc.edu:/pub/Linux/Incoming/ups-2.45.2-linux-0.2.diff.gz

and likely soon at:

  sunsite.unc.edu:/pub/Linux/devel/debuggers/ups-2.45.2-linux-0.2.diff.gz

These diffs should be applied to a virgin UPS distribution such as:

  ftp.x.org:/contrib/ups-2.45.2.tar.Z

Changes since the previous version:

* support for attaching to already running processes
* calling target functions (your own code) from a breakpoint works
* the special include directory is no longer needed with libc 4.5.17 or later
* the Imakefiles probably work
* UPS now pretends to understand `long long' and `unsigned long long' types
* UPS quietly tolerates the `long double' type
* UPS understands octal numbers in debugging stabs

There are only two real problems with UPS on Linux.  One is due to
a limitation in UPS and the other is due to a limitation in Linux.

* Linux makes use of inlined functions in the libc include files.  UPS
  does not correctly handle the case of executable code lines occuring
  in an included file.  Fixing this problem would be non-trivial so I
  didn't do it.  The symptom is that one freqently gets the message
  `No executable code on line' when trying to set a breakpoint.  As a
  work-around you can include a small dummy function at the beginning
  of any file which shows this problem, e.g. `static void dummy(void) {}'.

* When the debugged program is running of its own accord and doesn't
  hit a breakpoint, it is impossible to stop the program from UPS.
  This is because Linux does not (yet) support asynch I/O.  As a
  workaround, you can send a signal to the process from another window
  with `kill -STOP <pid-of-program>'.

After the last announcement I got several bug reports about garbage on
the screen after a menu was removed.  All these reports originated
from people with the then pre-beta XS3 server.  I never discovered
what the problem was since I couldn't duplicate it.

I would like to give special thanks to Karl Olav Lillevold
<Karl.Lillevold@nta.no> who reported most of the problems and helped
me with testing.

Rick Sladkey <jrs@world.std.com>
-----
diff -rcN orig/ups-2.45.2/lib/libmtrprog/ifdefs.h ups-2.45.2/lib/libmtrprog/ifdefs.h
*** orig/ups-2.45.2/lib/libmtrprog/ifdefs.h	Fri Sep 18 12:16:47 1992
--- ups-2.45.2/lib/libmtrprog/ifdefs.h	Sun Jan 16 22:21:28 1994
***************
*** 57,62 ****
--- 57,67 ----
  #define clipper		1
  #endif
  
+ #ifdef __linux__
+ #undef linux
+ #define linux
+ #endif
+ 
  /*  Which architecture?
   */
  #ifdef i386
***************
*** 82,87 ****
--- 87,98 ----
  #define THIS_ARCH	"bsdi386"
  #endif
  
+ #if defined(linux) && defined(i386)
+ #undef ARCH_LINUX386
+ #define ARCH_LINUX386	1
+ #define THIS_ARCH	"linux386"
+ #endif
+ 
  #if defined(sun) && defined(sparc)
  #undef ARCH_SUN4
  #define ARCH_SUN4	1
***************
*** 150,155 ****
--- 161,172 ----
  #ifdef bsdi
  #define OS_BSDI
  #define THIS_OS		"bsdi"
+ #define OS_BSD
+ #endif
+ 
+ #ifdef linux
+ #define OS_LINUX
+ #define THIS_OS		"linux"
  #define OS_BSD
  #endif
  
diff -rcN orig/ups-2.45.2/lib/libx11wn/wn_event.c ups-2.45.2/lib/libx11wn/wn_event.c
*** orig/ups-2.45.2/lib/libx11wn/wn_event.c	Wed Jul  1 08:28:34 1992
--- ups-2.45.2/lib/libx11wn/wn_event.c	Sun Jan 16 22:21:28 1994
***************
*** 1012,1025 ****
--- 1012,1029 ----
  
  	if (func != NULL) {
  		set_intr_event_mask(w);
+ #ifdef FASYNC
  		old_io_func = signal(SIGIO, catch_sigio);
  		if (fcntl(fd, F_SETFL, FASYNC) != 0)
  			wn__panic("FASYNC on botch");
+ #endif
  	}
  	else {
+ #ifdef FASYNC
  		(void) signal(SIGIO, old_io_func);
  		if (fcntl(fd, F_SETFL, 0) != 0)
  			wn__panic("FASYNC off botch");
+ #endif
  		set_normal_event_mask(w);
  	}
  
diff -rcN orig/ups-2.45.2/lib/libx11wn/wn_init.c ups-2.45.2/lib/libx11wn/wn_init.c
*** orig/ups-2.45.2/lib/libx11wn/wn_init.c	Tue Sep 15 13:05:47 1992
--- ups-2.45.2/lib/libx11wn/wn_init.c	Sun Jan 16 22:21:29 1994
***************
*** 667,672 ****
--- 667,673 ----
  #endif
  	}
  
+ #ifdef FASYNC
  	if (fcntl(fd, F_SETOWN, getpid()) != 0) {
  		if (errbuf != NULL) {
  			sprintf(errbuf,
***************
*** 675,680 ****
--- 676,682 ----
  		}
  		return -1;
  	}
+ #endif
  
  	_wn_change_wn_fdmask(fd);
  	return 0;
diff -rcN orig/ups-2.45.2/lib/libx11wn/wn_misc.c ups-2.45.2/lib/libx11wn/wn_misc.c
*** orig/ups-2.45.2/lib/libx11wn/wn_misc.c	Sat Apr 25 10:09:24 1992
--- ups-2.45.2/lib/libx11wn/wn_misc.c	Sun Jan 16 22:21:29 1994
***************
*** 54,61 ****
--- 54,63 ----
  /*  BUG: this should be in ansi/stddef.h, but select() is so undefined
   *  that I don't want it there.
   */
+ #ifndef linux
  int select PROTO((int nfds, int *ifds, int *ofds, int *efds,
  							struct timeval *timeout));
+ #endif
  
  static char *store_set_selection PROTO((const char *data, int nbytes));
  static char *store_got_selection PROTO((const char *data, int nbytes));
diff -rcN orig/ups-2.45.2/ups/core.c ups-2.45.2/ups/core.c
*** orig/ups-2.45.2/ups/core.c	Tue Sep 15 14:04:05 1992
--- ups-2.45.2/ups/core.c	Sun Jan 16 22:21:31 1994
***************
*** 31,37 ****
  #include <signal.h>
  #include <errno.h>
  
! #ifndef OS_BSDI
  #include <sys/vmparam.h>
  #endif
  
--- 31,37 ----
  #include <signal.h>
  #include <errno.h>
  
! #if !defined(OS_BSDI) && !defined(OS_LINUX)
  #include <sys/vmparam.h>
  #endif
  
***************
*** 75,81 ****
  
  #undef USERCORE
  #if defined(OS_BSDI) || defined(OS_ULTRIX) || defined(ARCH_CLIPPER) || \
!     defined(ARCH_VAX) || defined(OS_RISCOS) || defined(OS_NEWSOS)
  #define USERCORE
  #endif
  
--- 75,82 ----
  
  #undef USERCORE
  #if defined(OS_BSDI) || defined(OS_ULTRIX) || defined(ARCH_CLIPPER) || \
!     defined(ARCH_VAX) || defined(OS_RISCOS) || defined(OS_NEWSOS) || \
!     defined(OS_LINUX)
  #define USERCORE
  #endif
  
diff -rcN orig/ups-2.45.2/ups/exec.c ups-2.45.2/ups/exec.c
*** orig/ups-2.45.2/ups/exec.c	Thu Sep 17 17:00:14 1992
--- ups-2.45.2/ups/exec.c	Sun Jan 30 23:38:18 1994
***************
*** 103,109 ****
  		errf("Target not running");
  }
  
! #ifndef OS_SUNOS
  /* ARGSUSED */
  #endif
  int
--- 103,109 ----
  		errf("Target not running");
  }
  
! #if !defined(OS_SUNOS) && !defined(OS_LINUX)
  /* ARGSUSED */
  #endif
  int
***************
*** 111,117 ****
  const char *name;
  int pid;
  {
! #ifndef OS_SUNOS
  	errf("This machine does not support attaching to running processes");
  	return -1;
  #else
--- 111,117 ----
  const char *name;
  int pid;
  {
! #if !defined(OS_SUNOS) && !defined(OS_LINUX)
  	errf("This machine does not support attaching to running processes");
  	return -1;
  #else
***************
*** 146,152 ****
  	proc_set_base_sp(Current_proc, get_outer_fp());
  
  	return 0;
! #endif /* !OS_SUNOS */
  }
  
  void
--- 146,152 ----
  	proc_set_base_sp(Current_proc, get_outer_fp());
  
  	return 0;
! #endif /* !OS_SUNOS && !OS_LINUX */
  }
  
  void
diff -rcN orig/ups-2.45.2/ups/mreg.h ups-2.45.2/ups/mreg.h
*** orig/ups-2.45.2/ups/mreg.h	Mon May  4 13:40:03 1992
--- ups-2.45.2/ups/mreg.h	Sun Jan 16 22:21:32 1994
***************
*** 36,41 ****
--- 36,52 ----
  #define N_UREGS			(N_UAREA_GREGS + 1)
  #endif
  
+ #ifdef OS_LINUX
+ #define N_UAREA_GREGS		17
+ #define UR_SP			15
+ #define UR_FP			5
+ #define UR_PC			12
+ #define N_UREGS			17
+ #define UPAGES 1
+ #define ctob(x)	(0x1000*(x))
+ #define USRSTACK 0xc0000000
+ #endif
+ 
  #ifdef ARCH_CLIPPER
  #define N_UAREA_GREGS		14	/* Clipper has r0..r13 as general regs */
  
***************
*** 71,77 ****
   *  We try to abstract out some common code for these, and define
   *  UAREA_REGS for #ifdefs.
   */
! #if defined(OS_BSDI) || defined(ARCH_VAX) || defined(ARCH_MIPS) || defined(ARCH_CLIPPER)
  #define UAREA_REGS
  #endif
  
--- 82,89 ----
   *  We try to abstract out some common code for these, and define
   *  UAREA_REGS for #ifdefs.
   */
! #if defined(OS_BSDI) || defined(ARCH_VAX) || defined(ARCH_MIPS) || \
!     defined(ARCH_CLIPPER) || defined(OS_LINUX)
  #define UAREA_REGS
  #endif
  
diff -rcN orig/ups-2.45.2/ups/obj_env.c ups-2.45.2/ups/obj_env.c
*** orig/ups-2.45.2/ups/obj_env.c	Sun Jul 26 12:55:55 1992
--- ups-2.45.2/ups/obj_env.c	Sun Jan 16 22:21:32 1994
***************
*** 27,33 ****
--- 27,35 ----
  #include "menudata.h"
  #include "tdr.h"
  
+ #ifndef OS_LINUX
  extern const char **environ;
+ #endif
  
  /*  An element in the circular doubly linked list of environment entries.
   */
diff -rcN orig/ups-2.45.2/ups/obj_signal.c ups-2.45.2/ups/obj_signal.c
*** orig/ups-2.45.2/ups/obj_signal.c	Sun Jul 26 12:50:21 1992
--- ups-2.45.2/ups/obj_signal.c	Sun Jan 16 22:21:33 1994
***************
*** 46,51 ****
--- 46,88 ----
  
  #define SIG_DFL_NO_EFFECT	  0	/* sig doesn't terminate proc by default */
  
+ #ifdef OS_LINUX
+ static siginfo_t Sigtab[] = {
+ 	"",		  0,		
+ 	"SIGHUP    (1) ", SIG_DFL_TERMINATES | SIG_CONT | SIG_ACCEPT,
+ 	"SIGINT    (2) ", SIG_DFL_TERMINATES,
+ 	"SIGQUIT   (3) ", SIG_DFL_TERMINATES | SIG_DFL_CORE,
+ 	"SIGILL    (4) ", SIG_DFL_TERMINATES | SIG_DFL_CORE,
+ 	"SIGTRAP   (5) ", SIG_DFL_TERMINATES | SIG_DFL_CORE,
+ 	"SIGIOT    (6) ", SIG_DFL_TERMINATES | SIG_DFL_CORE,
+ 	"SIGUNUSED (7) ", SIG_DFL_TERMINATES | SIG_DFL_CORE | SIG_CONT | SIG_ACCEPT,
+ 	"SIGFPE    (8) ", SIG_DFL_TERMINATES | SIG_DFL_CORE | SIG_CONT | SIG_ACCEPT,
+ 	"SIGKILL   (9) ", SIG_DFL_TERMINATES | SIG_CONT | SIG_ACCEPT,
+ 	"SIGUSR1   (10)", SIG_DFL_TERMINATES,
+ 	"SIGSEGV   (11)", SIG_DFL_TERMINATES | SIG_DFL_CORE,
+ 	"SIGUSR2   (12)", SIG_DFL_TERMINATES,
+ 	"SIGPIPE   (13)", SIG_DFL_TERMINATES,
+ 	"SIGALRM   (14)", SIG_DFL_TERMINATES | SIG_CONT | SIG_ACCEPT,
+ 	"SIGTERM   (15)", SIG_DFL_TERMINATES,
+ 	"SIGSTKFLT (16)", SIG_DFL_NO_EFFECT  | SIG_CONT | SIG_ACCEPT,
+ 	"SIGCHLD   (17)", SIG_DFL_NO_EFFECT  | SIG_CONT | SIG_ACCEPT,
+ 	"SIGCONT   (18)", SIG_DFL_NO_EFFECT  | SIG_CONT | SIG_ACCEPT,
+ 	"SIGSTOP   (19)", SIG_DFL_STOPS,	
+ 	"SIGTSTP   (20)", SIG_DFL_STOPS      | SIG_CONT | SIG_ACCEPT,	
+ 	"SIGTTIN   (21)", SIG_DFL_STOPS,
+ 	"SIGTTOU   (22)", SIG_DFL_STOPS,
+ 	"SIGIO     (23)", SIG_DFL_NO_EFFECT  | SIG_CONT | SIG_ACCEPT,	
+ 	"SIGXCPU   (24)", SIG_DFL_TERMINATES,	
+ 	"SIGXFSZ   (25)", SIG_DFL_TERMINATES,	
+ 	"SIGVTALARM(26)", SIG_DFL_TERMINATES | SIG_CONT | SIG_ACCEPT,	
+ 	"SIGPROF   (27)", SIG_DFL_TERMINATES,	
+ 	"SIGWINCH  (28)", SIG_DFL_NO_EFFECT  | SIG_CONT | SIG_ACCEPT,	
+ 	"SIGLOST   (29)", SIG_DFL_TERMINATES,
+ 	"SIGPWR    (30)", SIG_DFL_TERMINATES,	
+ 	"SIG31     (31)", SIG_DFL_TERMINATES,	
+ 	"SIG32     (32)", SIG_DFL_TERMINATES,	
+ };
+ #else
  static siginfo_t Sigtab[] = {
  	"",		  0,		
  	"SIGHUP    (1) ", SIG_DFL_TERMINATES | SIG_CONT | SIG_ACCEPT,
***************
*** 80,85 ****
--- 117,123 ----
  	"SIGUSR1   (30)", SIG_DFL_TERMINATES,	
  	"SIGUSR2   (31)", SIG_DFL_TERMINATES,	
  };
+ #endif
  
  const char Sig_format[] = "signal %[-]15cs%[-]46cs\n";
  
***************
*** 142,148 ****
  sig_is_fatal(sig)
  int sig;
  {
! 	return sig == SIGILL || sig == SIGSEGV || sig == SIGBUS;
  }
  
  const char *
--- 180,196 ----
  sig_is_fatal(sig)
  int sig;
  {
! 	return 0
! #ifdef SIGILL
! 		|| sig == SIGILL
! #endif
! #ifdef SIGSEGV
! 		|| sig == SIGSEGV
! #endif
! #ifdef SIGBUG
! 		|| sig == SIGBUS
! #endif
! 			;
  }
  
  const char *
diff -rcN orig/ups-2.45.2/ups/obj_target.c ups-2.45.2/ups/obj_target.c
*** orig/ups-2.45.2/ups/obj_target.c	Sun Jul 26 13:01:27 1992
--- ups-2.45.2/ups/obj_target.c	Sun Jan 16 22:21:33 1994
***************
*** 36,41 ****
--- 36,45 ----
  #include "state.h"
  #include "tdr.h"
  
+ #ifdef OS_LINUX
+ #define NCARGS ARG_MAX
+ #endif
+ 
  static int args_quitfunc PROTO((struct edescst *edesc, int unused_n_tries));
  static void args_edit PROTO((struct drawst fdets));
  
diff -rcN orig/ups-2.45.2/ups/proc.c ups-2.45.2/ups/proc.c
*** orig/ups-2.45.2/ups/proc.c	Thu Sep 17 17:03:02 1992
--- ups-2.45.2/ups/proc.c	Sun Jan 30 22:37:06 1994
***************
*** 49,55 ****
--- 49,57 ----
  #include <signal.h>
  #include <sys/dir.h>		/* VAX needs this for user.h */
  #include <sys/user.h>
+ #ifndef OS_LINUX
  #include <machine/reg.h>
+ #endif
  #include <errno.h>
  extern int errno;	/* some versions on errno.h don't declare this */
  
***************
*** 87,93 ****
  #include <sys/ptrace.h>
  #endif
  
! #ifndef OS_SUNOS
  
  /*  Word size (and alignment) for ptrace read/write data requests.
   *
--- 89,101 ----
  #include <sys/ptrace.h>
  #endif
  
! #ifdef OS_LINUX
! #include <sys/ptrace.h>
! #define PTRACE_PEEKUSER PTRACE_PEEKUSR
! #define PTRACE_POKEUSER PTRACE_POKEUSR
! #endif
! 
! #if !defined(OS_SUNOS)
  
  /*  Word size (and alignment) for ptrace read/write data requests.
   *
***************
*** 95,100 ****
--- 103,109 ----
   */
  #define WORDSIZE	4
  
+ #ifndef OS_LINUX
  #if defined(ARCH_MIPS) && (defined(OS_ULTRIX) || defined(OS_RISCOS))
  /* Request values for the ptrace system call
   */
***************
*** 137,149 ****
--- 146,163 ----
  	PTRACE_SINGLESTEP =	9	/* single step process */
  };
  #endif /* !(OS_ULTRIX && OS_MIPS) */
+ #endif /* !OS_LINUX */
  #endif /* !OS_SUNOS */
  
  #ifndef WSTOPSIG
  #define WSTOPSIG(w)	((w).w_stopsig)
  #endif
  
+ #ifdef OS_LINUX
+ typedef int ptracereq_t;
+ #else
  typedef enum ptracereq ptracereq_t;
+ #endif
  
  #ifdef PTRACE_DEBUG
  static int ptrace_debug PROTO((int request, int pid, int addr, int data));
***************
*** 154,162 ****
--- 168,180 ----
  int ptrace PROTO((ptracereq_t req, int pid, char *addr, int data, char *addr2));
  #define std_ptrace(req, pid, addr, data)	ptrace(req, pid, addr, data, (char *)NULL)
  #else
+ #ifdef OS_LINUX
+ #define std_ptrace(req, pid, addr, data)	ptrace(req, pid, (int) addr, data)
+ #else
  int ptrace PROTO((ptracereq_t req, int pid, char *addr, int data));
  #define std_ptrace(req, pid, addr, data)	ptrace(req, pid, addr, data)
  #endif
+ #endif
  
  /*  Return the offset into the u area of member.
   *  Used when doing PEEKUSER ptrace requests.
***************
*** 193,199 ****
  #define INTEGER_REG(sr, regno)	((&(sr)->sr_regs.r_y)[regno])
  #endif
  
! #if defined(OS_SUNOS) || defined(OS_BSDI)
  typedef int wait_arg_t;
  #define WAIT_STATUS_IS_INT
  #else
--- 211,217 ----
  #define INTEGER_REG(sr, regno)	((&(sr)->sr_regs.r_y)[regno])
  #endif
  
! #if defined(OS_SUNOS) || defined(OS_BSDI) || defined(OS_LINUX)
  typedef int wait_arg_t;
  #define WAIT_STATUS_IS_INT
  #else
***************
*** 279,284 ****
--- 297,309 ----
  #define GET_OPCODE_FROM_WORD(w)		((w) & 0xff)
  #endif
  
+ #ifdef ARCH_LINUX386
+ #define BPT				0xcc		/* int $3 */
+ #define BPT_PC_OFFSET			1
+ #define PUT_OPCODE_IN_WORD(w, data)	(((w) & ~0xff) | (data & 0xff))
+ #define GET_OPCODE_FROM_WORD(w)		((w) & 0xff)
+ #endif
+ 
  #ifdef ARCH_SUN386
  #define BPT				0xcc		/* int $3 */
  #define BPT_PC_OFFSET			1
***************
*** 396,401 ****
--- 421,434 ----
  {
  	int res;
  
+ #ifdef ARCH_LINUX386
+ 	if (req == PTRACE_CONT || req == PTRACE_SINGLESTEP) {
+ 		if (addr != (char *) 1) {
+ 			std_ptrace(PTRACE_POKEUSER, pid, 4*EIP, addr);
+ 			addr = (char *) 1;
+ 		}
+ 	}
+ #endif
  	errno = 0;
  	res = std_ptrace(req, pid, addr, data);
  	if (errno != 0)
***************
*** 456,461 ****
--- 489,500 ----
  		ur[i].ur_uaddr = (int)U_OFFSET(u_pcb.pcb_regs[i]);
  	ur[UR_PC].ur_uaddr = (int)U_OFFSET(u_pcb.pcb_cxt.cxt_pc);
  #endif
+ #ifdef ARCH_LINUX386
+ 	int i;
+ 
+ 	for (i = 0; i <= 16; i++)
+ 		ur[i].ur_uaddr = 4*i;
+ #endif
  }
  #endif /* !ARCH_BSDI386 */
  
***************
*** 1084,1090 ****
  	return ((iproc_t *)proc)->ip_base_sp;
  }
  
! #ifdef OS_SUNOS
  proc_t
  proc_attach(path, pid, p_whystopped)
  const char *path;
--- 1123,1129 ----
  	return ((iproc_t *)proc)->ip_base_sp;
  }
  
! #if defined(OS_SUNOS) || defined(OS_LINUX)
  proc_t
  proc_attach(path, pid, p_whystopped)
  const char *path;
***************
*** 1100,1106 ****
  	*p_whystopped = ip->ip_whystopped;
  	return (proc_t)ip;
  }
! #endif /* OS_SUNOS */
  
  /*  Kill off the target process
   */
--- 1139,1145 ----
  	*p_whystopped = ip->ip_whystopped;
  	return (proc_t)ip;
  }
! #endif /* OS_SUNOS || OS_LINUX */
  
  /*  Kill off the target process
   */
***************
*** 1565,1571 ****
  #ifdef ARCH_CLIPPER
  	taddr_t saved_sp, saved_regs[N_REG_ARGS];
  #endif
! #ifdef ARCH_BSDI386
  	taddr_t saved_regs[N_UREGS];
  #endif
  	breakpoint_t breakpoint;
--- 1604,1610 ----
  #ifdef ARCH_CLIPPER
  	taddr_t saved_sp, saved_regs[N_REG_ARGS];
  #endif
! #if defined(ARCH_BSDI386) || defined(ARCH_LINUX386)
  	taddr_t saved_regs[N_UREGS];
  #endif
  	breakpoint_t breakpoint;
***************
*** 1657,1663 ****
  		saved_regs[i] = proc_getreg(proc, i);
  	sp = saved_sp = proc_getreg(proc, REG_SP);
  #endif
! #ifdef ARCH_BSDI386
  	for (i = 0; i < N_UREGS; ++i)
  		if (get_uarea_reg(ip, i, &saved_regs[i]) != 0)
  			panic("can't get reg in pcf");
--- 1696,1702 ----
  		saved_regs[i] = proc_getreg(proc, i);
  	sp = saved_sp = proc_getreg(proc, REG_SP);
  #endif
! #if defined(ARCH_BSDI386) || defined(ARCH_LINUX386)
  	for (i = 0; i < N_UREGS; ++i)
  		if (get_uarea_reg(ip, i, &saved_regs[i]) != 0)
  			panic("can't get reg in pcf");
***************
*** 1761,1767 ****
  		return -1;
  	}
  #endif /* ARCH_VAX */
! #if defined(ARCH_SUN3) || defined(ARCH_SUN386) || defined(ARCH_CLIPPER) || defined(ARCH_BSDI386)
  	sp -= 4;
  	if (proc_write_data(proc, sp, (char *)&retpc, sizeof(retpc)) != 0) {
  		*p_mesg = "Can't push return address";
--- 1800,1807 ----
  		return -1;
  	}
  #endif /* ARCH_VAX */
! #if defined(ARCH_SUN3) || defined(ARCH_SUN386) || defined(ARCH_CLIPPER) || \
!     defined(ARCH_BSDI386) || defined(ARCH_LINUX386)
  	sp -= 4;
  	if (proc_write_data(proc, sp, (char *)&retpc, sizeof(retpc)) != 0) {
  		*p_mesg = "Can't push return address";
***************
*** 1793,1799 ****
  	proc_setreg(proc, REG_FP, fp);
  	proc_setreg(proc, REG_SP, sp);
  #endif /* ARCH_VAX */
! #if defined(ARCH_SUN3) || defined(ARCH_SUN386) || defined(ARCH_BSDI386)
  	proc_setreg(proc, REG_SP, sp);
  #endif
  #ifdef ARCH_MIPS
--- 1833,1840 ----
  	proc_setreg(proc, REG_FP, fp);
  	proc_setreg(proc, REG_SP, sp);
  #endif /* ARCH_VAX */
! #if defined(ARCH_SUN3) || defined(ARCH_SUN386) || defined(ARCH_BSDI386) || \
!     defined(ARCH_LINUX386)
  	proc_setreg(proc, REG_SP, sp);
  #endif
  #ifdef ARCH_MIPS
***************
*** 1908,1913 ****
--- 1949,1959 ----
  		if (set_uarea_reg(ip, i, saved_regs[i]) != 0)
  			panic("can't restore regs in cf");
  #endif
+ #ifdef ARCH_LINUX386
+ 	for (i = 0; i < N_UREGS; ++i)
+ 		if (i != ORIG_EAX && set_uarea_reg(ip, i, saved_regs[i]) != 0)
+ 			panic("can't restore regs in cf");
+ #endif
  
  	/*  Wait for target will have set ip_restart_pc to retpc, because
  	 *  that is where the function returned.  We put this back.
***************
*** 1952,1958 ****
  proc_get_retaddr_after_jsr(proc)
  proc_t proc;
  {
! #if defined(ARCH_SUN3) || defined(ARCH_SUN386) || defined(ARCH_CLIPPER) || defined(ARCH_BSDI386)
  	taddr_t sp, retaddr;
  
  	sp = proc_getreg(proc, REG_SP);
--- 1998,2005 ----
  proc_get_retaddr_after_jsr(proc)
  proc_t proc;
  {
! #if defined(ARCH_SUN3) || defined(ARCH_SUN386) || defined(ARCH_CLIPPER) || \
!     defined(ARCH_BSDI386) || defined(ARCH_LINUX386)
  	taddr_t sp, retaddr;
  
  	sp = proc_getreg(proc, REG_SP);
***************
*** 2136,2142 ****
--- 2183,2193 ----
  #ifdef ARCH_SUN4
  	uaddr = U_OFFSET(u_signal[sig]) + sparc_u_offset();
  #else
+ #ifdef ARCH_LINUX386
+ 	uaddr = 0; /* XXX */
+ #else
  	uaddr = U_OFFSET(u_signal[sig]);
+ #endif
  #endif
  #endif
  #endif
diff -rcN orig/ups-2.45.2/ups/st_parse.c ups-2.45.2/ups/st_parse.c
*** orig/ups-2.45.2/ups/st_parse.c	Tue Feb  9 15:47:58 1993
--- ups-2.45.2/ups/st_parse.c	Sat Jan 29 08:59:47 1994
***************
*** 255,262 ****
  	s = *p_s;
  	if (!isdigit(*s))
  		panic("bad number in parse_num");
! 	while (*s != '\0' && isdigit(*s))
! 		res = res * 10 + *s++ - '0';
  	*p_s = s;
  	return res;
  }
--- 255,284 ----
  	s = *p_s;
  	if (!isdigit(*s))
  		panic("bad number in parse_num");
! 	if (*s == '0') {
! 		s++;
! 		if (*s == 'x' || *s == 'X') {
! 			s++;
! 			for (;;) {
! 				if (isdigit(*s))
! 					res = res * 16 + *s++ - '0';
! 				else if (*s >= 'A' && *s <= 'F')
! 					res = res * 16 + *s++ - 'A' + 10;
! 				else if (*s >= 'a' && *s <= 'f')
! 					res = res * 16 + *s++ - 'a' + 10;
! 				else
! 					break;
! 			}
! 		}
! 		else {
! 			while (*s >= '0' && *s <= '7')
! 				res = res * 8 + *s++ - '0';
! 		}
! 	}
! 	else {
! 		while (isdigit(*s))
! 			res = res * 10 + *s++ - '0';
! 	}
  	*p_s = s;
  	return res;
  }
***************
*** 379,384 ****
--- 401,410 ----
  		0,		-1,		TY_UINT,	sizeof(long),
  		4,		0,		TY_FLOAT,	sizeof(float),
  		8,		0,		TY_DOUBLE,	sizeof(double),
+ #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
+ 		12,		0,		TY_LONG_DOUBLE,
+ 			sizeof(long double),
+ #endif
  	};
  #define N_C_TYPES	(sizeof c_typetab / sizeof *c_typetab)
  	static f77_typetab_t f77_typetab[] = {
diff -rcN orig/ups-2.45.2/ups/st_skim.c ups-2.45.2/ups/st_skim.c
*** orig/ups-2.45.2/ups/st_skim.c	Tue Sep 15 13:58:19 1992
--- ups-2.45.2/ups/st_skim.c	Sun Jan 30 00:37:12 1994
***************
*** 563,568 ****
--- 563,569 ----
  				name = symstring(st->st_symio_id, symno);
  				stf->stf_name = name;
  
+ #ifdef CFRONT_KLUDGES
  				/*  We don't change the filename for .h files.
  				 *  DJ Delorie <dj@ctron.com> says this makes
  				 *  ups work better with cfront (c++).
***************
*** 570,575 ****
--- 571,582 ----
  				if (name != NULL &&
  				    strcmp(name + strlen(name) - 2, ".h") != 0)
  					sfiles->fi_name = stf->stf_name;
+ #else
+ 				/*  We need to changes filenames for .h files,
+ 				 *  otherwise inline functions don't work.
+ 				 */
+ 				sfiles->fi_name = stf->stf_name;
+ #endif
  			}
  			break;
  
diff -rcN orig/ups-2.45.2/ups/stack.c ups-2.45.2/ups/stack.c
*** orig/ups-2.45.2/ups/stack.c	Wed May 20 17:11:43 1992
--- ups-2.45.2/ups/stack.c	Sun Jan 16 22:21:36 1994
***************
*** 22,28 ****
--- 22,30 ----
  #include <machine/machparam.h>
  #include <machine/vmparam.h>	/* for USRSTACK */
  #else
+ #ifndef OS_LINUX
  #include <machine/frame.h>
+ #endif
  #endif /* !ARCH_CLIPPER */
  #endif /* !ARCH_MIPS */
  
***************
*** 47,53 ****
  #include "mips_frame.h"
  #endif /* ARCH_MIPS */
  
! #ifdef ARCH_BSDI386
  /*  There is no <machine/frame.h> on the BSDi box.  This is what a
   *  stack frame looks like.  Don't add to this - the signal handling
   *  code in build_stack_trace depends on the size of this struct.
--- 49,55 ----
  #include "mips_frame.h"
  #endif /* ARCH_MIPS */
  
! #if defined(ARCH_BSDI386) || defined(ARCH_LINUX386)
  /*  There is no <machine/frame.h> on the BSDi box.  This is what a
   *  stack frame looks like.  Don't add to this - the signal handling
   *  code in build_stack_trace depends on the size of this struct.
***************
*** 383,389 ****
--- 385,393 ----
  	preamble_t *pr;
  	bool must_find_fp;
  #endif
+ #ifndef OS_LINUX
  	struct sigcontext scbuf;
+ #endif
  	int lnum;
  	bool normal_frame;
  	taddr_t pc, fp, sp;
***************
*** 427,432 ****
--- 431,442 ----
  		}
  #if defined(ARCH_VAX) || defined(ARCH_CLIPPER) || defined(ARCH_BSDI386)
  		if (*f->fu_name == '[' && strcmp(f->fu_name, "[start]") == 0) {
+ 			fp = NULL;
+ 			break;
+ 		}
+ #endif
+ #ifdef ARCH_LINUX386
+ 		if (strcmp(f->fu_name, "_entry") == 0) {
  			fp = NULL;
  			break;
  		}
diff -rcN orig/ups-2.45.2/ups/symtab.h ups-2.45.2/ups/symtab.h
*** orig/ups-2.45.2/ups/symtab.h	Thu Sep 17 08:36:24 1992
--- ups-2.45.2/ups/symtab.h	Sat Jan 29 09:24:59 1994
***************
*** 66,73 ****
--- 66,76 ----
  	TY_UINT,		/* unsigned int */
  	TY_LONG,		/* long integer */
  	TY_ULONG,	/* unsigned long */
+ 	TY_LONG_LONG,	/* long long integer */
+ 	TY_ULONG_LONG,	/* long long integer */
  	TY_FLOAT,	/* floating point */
  	TY_DOUBLE,	/* double word */
+ 	TY_LONG_DOUBLE,	/* long double floating point */
  	TY_INT_ASSUMED,	/* unknown - int assumed */
  
  /* FORTRAN base types */
diff -rcN orig/ups-2.45.2/ups/text.c ups-2.45.2/ups/text.c
*** orig/ups-2.45.2/ups/text.c	Wed May 20 17:11:41 1992
--- ups-2.45.2/ups/text.c	Sun Jan 16 22:21:36 1994
***************
*** 149,154 ****
--- 149,158 ----
  #define MOVL_ESP_EBP	0x89e5
  #endif
  
+ #ifdef OS_LINUX
+ #define MOVL_ESP_EBP	0x89e5
+ #endif
+ 
  #define SWAP_SHORT(x)		((x >> 8) | (((x) & 0xff) << 8))
  #define SW_MOVL_ESP_EBP		SWAP_SHORT(MOVL_ESP_EBP)
  #define SW_SUBL_IMM_ESP		SWAP_SHORT(SUBL_IMM_ESP)
diff -rcN orig/ups-2.45.2/ups/ups.c ups-2.45.2/ups/ups.c
*** orig/ups-2.45.2/ups/ups.c	Sun Sep 13 15:17:47 1992
--- ups-2.45.2/ups/ups.c	Sun Jan 16 22:21:37 1994
***************
*** 130,140 ****
--- 130,150 ----
  		 */
  
  		switch (sig) {
+ #ifdef SIGSEGV
  		case SIGSEGV:	sigstr = "segmentation fault";		break;
+ #endif
+ #ifdef SIGBUG
  		case SIGBUS:	sigstr = "bus error";			break;
+ #endif
+ #ifdef SIGILL
  		case SIGILL:	sigstr = "illegal instruction";		break;
+ #endif
+ #ifdef SIGFPE
  		case SIGFPE:	sigstr = "floating point exception";	break;
+ #endif
+ #ifdef SIGQUIT
  		case SIGQUIT:	sigstr = "SIGQUIT";			break;
+ #endif
  		default:	sigstr = NULL;				break;
  		}
  
***************
*** 308,314 ****
  char **argv;
  {
  	static const int siglist[] = {
! 		SIGQUIT, SIGILL, SIGIOT, SIGEMT, SIGFPE, SIGSEGV, SIGSYS, SIGBUS,
  	};
  	static const char *(*vfuncs[])PROTO((void)) = {
  		arg_version, 
--- 318,347 ----
  char **argv;
  {
  	static const int siglist[] = {
! #ifdef SIGQUIT
! 		SIGQUIT,
! #endif
! #ifdef SIGILL
! 		SIGILL,
! #endif
! #ifdef SIGIOT
! 		SIGIOT,
! #endif
! #ifdef SIGEMT
! 		SIGEMT,
! #endif
! #ifdef SIGFPE
! 		SIGFPE,
! #endif
! #ifdef SIGSEGV
! 		SIGSEGV,
! #endif
! #ifdef SIGSYS
! 		SIGSYS,
! #endif
! #ifdef SIGBUG
! 		SIGBUS,
! #endif
  	};
  	static const char *(*vfuncs[])PROTO((void)) = {
  		arg_version, 
diff -rcN orig/ups-2.45.2/ups/va_val.c ups-2.45.2/ups/va_val.c
*** orig/ups-2.45.2/ups/va_val.c	Tue Sep 15 14:00:34 1992
--- ups-2.45.2/ups/va_val.c	Sat Jan 29 09:10:45 1994
***************
*** 446,451 ****
--- 446,459 ----
  		if (DREAD_VAR(addr, vl.vl_int))
  			int_to_string(buf, sizeof(buf), vl.vl_int, dv->dv_format);
  		break;
+ 	case TY_LONG_LONG:
+ 	case TY_ULONG_LONG:
+ #if defined(__GNUC__) || defined(HAVE_LONG_LONG)
+ 		strcpy(buf, "<support for long long is unfinished>");
+ #else
+ 		strcpy(buf, "<recompile UPS with GCC to use long long>");
+ #endif
+ 		break;
  	case TY_UNION:
  	case TY_STRUCT:
  	case TY_U_STRUCT:
***************
*** 461,466 ****
--- 469,481 ----
  		if (dread_fpval(addr, v->va_class == CL_REG, TRUE,
  						   (char *)&vl.vl_double) == 0)
  			strcpy(buf, get_real(vl, want_hex, FALSE));
+ 		break;
+ 	case TY_LONG_DOUBLE:
+ #if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
+ 		strcpy(buf, "<support for long double is unfinished>");
+ #else
+ 		strcpy(buf, "<recompile UPS with GCC to use long double>");
+ #endif
  		break;
  	case TY_ENUM:
  	case TY_U_ENUM:
